package io.github.wanggit.antrpc.console.web;

import io.github.wanggit.antrpc.commons.bean.RegisterBeanMethod;
import io.github.wanggit.antrpc.commons.generic.IServiceProviderInvoker;
import io.github.wanggit.antrpc.commons.generic.InvokeDTO;
import io.github.wanggit.antrpc.commons.generic.InvokeDTOUtil;
import io.github.wanggit.antrpc.commons.utils.ApplicationNameUtil;
import io.github.wanggit.antrpc.commons.utils.JsonUtils;
import io.github.wanggit.antrpc.console.service.InterfaceService;
import io.github.wanggit.antrpc.console.web.utils.LoadBalancerUtil;
import io.github.wanggit.antrpc.console.web.vo.Result;
import io.github.wanggit.antrpc.console.web.vo.ZookeeperNodeVO;
import io.github.wanggit.antrpc.console.zookeeper.IAllNodeContainer;
import io.github.wanggit.antrpc.console.zookeeper.IInterfaceContainer;
import io.github.wanggit.antrpc.console.zookeeper.InterfaceDTO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

@Slf4j
@RestController
@RequestMapping("interface")
public class InterfaceController {

    @Autowired private IInterfaceContainer interfaceContainer;

    @Autowired private IServiceProviderInvoker serviceProviderInvoker;

    @Autowired private InterfaceService interfaceService;

    @Autowired private IAllNodeContainer allNodeContainer;

    /**
     * 服务提供端的限流设置，服务提供端设置之后，对所有服务消费者都生效
     *
     * @param className class name
     * @param humanFullMethodName human full method name
     * @param limit limit
     * @param durationInSeconds duration in seconds
     * @param appNameHostPort application_name@192.168.1.100:6060
     * @param type consumer or provider
     * @return result
     */
    @PostMapping("updateRateLimit")
    public Result updateRateLimit(
            @RequestParam("className") String className,
            @RequestParam("fullMethodName") String humanFullMethodName,
            @RequestParam("limit") Integer limit,
            @RequestParam("durationInSeconds") Integer durationInSeconds,
            @RequestParam("appHostInfo") String appNameHostPort,
            @RequestParam("type") String type) {
        if (Objects.equals("consumer", type)) {
            interfaceService.serviceConsumerUpdateRateLimit(
                    className, humanFullMethodName, limit, durationInSeconds, appNameHostPort);
        } else if (Objects.equals("provider", type)) {
            interfaceService.serviceProviderUpdateRateLimit(
                    className, humanFullMethodName, limit, durationInSeconds, appNameHostPort);
        }
        return Result.ok();
    }

    @PostMapping("deleteZkNode")
    public Result deleteZkNode(@RequestParam("path") String path) {
        interfaceService.deleteZkNode(path);
        return Result.ok();
    }

    @PostMapping("zk_data")
    public Result zookeeperData(@RequestParam("path") String path) {
        ZookeeperNodeVO zookeeperNodeVO = allNodeContainer.findByPath(path);
        if (null != zookeeperNodeVO) {
            zookeeperNodeVO.setData(
                    JsonUtils.toJsonPrettyString(
                            JsonUtils.fromJson(zookeeperNodeVO.getData(), Map.class)));
        }
        return Result.ok(zookeeperNodeVO);
    }

    @PostMapping("updateLoadBalancer")
    public Result updateLoadBalancer(
            @RequestParam("lb") String loadBalancerName, @RequestParam("clazz") String clazz) {
        if (!StringUtils.hasText(loadBalancerName) || !StringUtils.hasText(clazz)) {
            return Result.error("参数不正确.");
        }
        if (!LoadBalancerUtil.checkLoadBalancerValid(loadBalancerName)) {
            return Result.error("不存在的负载均衡器" + loadBalancerName + ".");
        }
        interfaceService.updateLoadbalancer(clazz, loadBalancerName);
        return Result.ok();
    }

    @PostMapping("opr")
    public Result serviceOnlineOrOffline(
            @RequestParam("opr") String opr,
            @RequestParam("host") String host,
            @RequestParam("clazz") String clazz) {
        if ("Y".equalsIgnoreCase(opr)) {
            interfaceService.classOnline(host, clazz);
        } else {
            interfaceService.classOffline(host, clazz);
        }
        return Result.ok();
    }

    /**
     * 设置权重
     *
     * @param weight
     * @return
     */
    @PostMapping("weight")
    public Result uploadWeight(
            @RequestParam("w") int weight,
            @RequestParam("host") String appNameHostPort,
            @RequestParam("clazz") String clazz) {
        interfaceService.updateWeight(clazz, appNameHostPort, weight);
        return Result.ok();
    }

    /**
     * 测试接口
     *
     * @param provider test_app@192.168.1.200:7076
     * @param className io.github.wanggit.antrpc.demo.api.LogReportService
     * @param methodName report(java.lang.String, java.lang.String)
     * @param arguments abc $$ xxx
     * @return result
     */
    @PostMapping("testInvoke")
    public Result testInvoke(
            @RequestParam("provider") String provider,
            @RequestParam("className") String className,
            @RequestParam("methodName") String methodName,
            @RequestParam("arguments") String arguments) {
        List<InterfaceDTO> interfaceDTOS =
                interfaceContainer.findContainsByInterfaceName(className);
        if (null == interfaceDTOS || interfaceDTOS.isEmpty()) {
            return Result.error("未找到服务提供者");
        }
        List<InterfaceDTO> providers =
                interfaceDTOS.stream()
                        .filter(
                                it ->
                                        Objects.equals(
                                                it.getAppName() + "@" + it.getHost(), provider))
                        .collect(Collectors.toList());
        if (providers.isEmpty()) {
            return Result.error(provider + "未提供此服务");
        }
        InterfaceDTO interfaceDTO = providers.get(0);
        List<RegisterBeanMethod> methods =
                interfaceDTO.getInterfaceMethodDTOS().stream()
                        .filter(it -> Objects.equals(it.getHumanFullName(), methodName))
                        .collect(Collectors.toList());
        if (methods.isEmpty()) {
            return Result.error(className + "未提供" + methodName + "方法");
        }
        RegisterBeanMethod methodDTO = methods.get(0);
        InvokeDTO invokeDTO = new InvokeDTO();
        invokeDTO.setArgumentValues(
                InvokeDTOUtil.getArgumentValues(methodDTO.getParameterTypeNames(), arguments));
        invokeDTO.setInterfaceName(className);
        invokeDTO.setMethodName(methodDTO.getMethodName());
        invokeDTO.setParameterTypeNames(methodDTO.getParameterTypeNames());
        invokeDTO.setHost(ApplicationNameUtil.getHost(provider));
        try {
            return Result.ok(serviceProviderInvoker.invoke(invokeDTO));
        } catch (Exception e) {
            if (log.isErrorEnabled()) {
                log.error("执行代码出错.", e);
            }
            return Result.error();
        }
    }
}
